package com.tg.appcommon.android;

import android.os.Build;
import android.os.Handler;
import android.os.Message;
import android.view.WindowManager;
import android.widget.Toast;
import java.lang.reflect.Field;
import java.lang.reflect.Method;


public class WindowBadTokenExceptionFixUtil {

    private static final String TAG = "WindowBadTokenExceptionFixUtil";

    public static void addToastWindowBadTokenExceptionCatch(Toast toast) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
            return;
        // API < 26 有这个Exception
        try {
            Field mTNField = Toast.class.getDeclaredField("mTN");
            mTNField.setAccessible(true);
            Object mTN = mTNField.get(toast);
            Class[] classes = Toast.class.getDeclaredClasses();
            Class tnClass = null;
            for (Class clazz : classes) {
                if (clazz.getName().contains("TN")) {
                    tnClass = clazz;
                    break;
                }
            }
            if (tnClass != null) {
                Field handlerField = tnClass.getDeclaredField("mHandler");
                handlerField.setAccessible(true);
                Handler handler = (Handler) handlerField.get(mTN);
                if (handler instanceof TNHandlerProxy)
                    return;
                TNHandlerProxy tnHandlerProxy = new TNHandlerProxy(handler);
                handlerField.set(mTN, tnHandlerProxy);
            }
        } catch (Exception e) {
            TGLog.e(TAG, "addToastWindowBadTokenExceptionCatch() reflection exception");
        }
    }

    private static class TNHandlerProxy extends Handler {

        private Handler mHandler;

        TNHandlerProxy(Handler handler) {
            super(handler.getLooper());
            mHandler = handler;
        }

        @Override
        public void handleMessage(Message msg) {
            try {
                TGLog.d(TAG, "TNHandlerProxy handleMessage() msg.what=" + msg.what);
                mHandler.handleMessage(msg);
            } catch (WindowManager.BadTokenException e) {
                /* ignore */
                TGLog.e(TAG, "TNHandlerProxy WindowManager.BadTokenException");
            }
        }
    }

    public static void addActivityWindowBadTokenExceptionCatch() {
        try {
            Class activityThreadClass = Class.forName("android.app.ActivityThread");
            final Method method = activityThreadClass.getMethod("currentActivityThread");
            method.setAccessible(true);
            Object activityThreadObj = method.invoke(null);
            Field mHField = activityThreadClass.getDeclaredField("mH");
            mHField.setAccessible(true);
            Handler handler = (Handler) mHField.get(activityThreadObj);
            Field callbackField = Handler.class.getDeclaredField("mCallback");
            callbackField.setAccessible(true);
            Handler.Callback callback = (Handler.Callback) callbackField.get(handler);
            if (!(callback instanceof HHandlerCallbackProxy)) {
                callbackField.set(handler, new HHandlerCallbackProxy(handler, callback));
            }
        } catch (Exception e) {
            TGLog.e(TAG, "addActivityWindowBadTokenExceptionCatch() reflection exception");
        }
    }

    private static class HHandlerCallbackProxy implements Handler.Callback {
        public static final int LAUNCH_ACTIVITY = 100;

        private Handler mH;
        private Handler.Callback mCallback;

        HHandlerCallbackProxy(Handler handler, Handler.Callback callback) {
            mH = handler;
            mCallback = callback;
        }

        @Override
        public boolean handleMessage(Message msg) {
            if (msg.what == LAUNCH_ACTIVITY) {
                try {
                    mH.handleMessage(msg);
                } catch (WindowManager.BadTokenException e) {
                    /* ignore */
                    TGLog.e(TAG, "HHandlerCallbackProxy WindowManager.BadTokenException");
                }
                TGLog.d(TAG, "HHandlerCallbackProxy handleMessage() msg.what=LAUNCH_ACTIVITY return true");
                return true;
            }
            if (mCallback != null) {
                TGLog.d(TAG, "HHandlerCallbackProxy handleMessage() msg.what=" + msg.what + " mCallback.handleMessage(msg)");
                return mCallback.handleMessage(msg);
            }
            TGLog.d(TAG, "HHandlerCallbackProxy handleMessage() msg.what=" + msg.what + " return false");
            return false;
        }
    }
}
